#ifndef _COMUTILIY_SERIALIZE_HPP_
#define _COMUTILIY_SERIALIZE_HPP_

#include <dlcom/cominc.h>


#define UCHAR_SIZE		sizeof(unsigned char)
#define USHORT_SIZE	sizeof(unsigned short)
#define UINT_SIZE		sizeof(unsigned int)


class Serialize
{
public:
	Serialize()
	{
		m_nBufSize	= 0;
		m_nDataSize = 0;
	}
	virtual ~Serialize(void)
	{
		m_pBuf.dispose();
	}
public:
	std_method_type_impl(unsigned char*) Buffer(unsigned int bOffset)
	{
		return m_pBuf.m_p + bOffset;
	}
	std_method_impl SetSize(unsigned int nSize)
	{
		HRESULT	hr = S_OK;
		rc_assert((m_nBufSize == 0 && m_pBuf == NULL), S_OK)
		m_pBuf = ALLOC_NEW unsigned char[nSize + 1]();
		rc_assert(m_pBuf.m_p != NULL, E_OUTOFMEMORY);
		m_nBufSize = nSize;
		return hr;
	}
	std_method_type_impl(unsigned int) GetSize() const
	{
		return m_nBufSize;
	}
	std_method_type_impl(unsigned int) GetDataSize() const
	{
		return m_nDataSize;
	}
	std_method_impl Attach(unsigned char* pBuf, unsigned int nSize)
	{
		rc_assert(pBuf, E_INVALIDARG);

		HRESULT	hr = S_OK;
		hr = Detach();
		rc_assert(hr == S_OK, E_FAIL)

		hr = SetSize(nSize);
		rc_assert(hr == S_OK, E_FAIL)
		
		s_memcpy(m_pBuf, pBuf, nSize);

		return S_OK;
	}
	std_method_impl Detach()
	{
		m_pBuf.dispose();
		m_pBuf = NULL;
		m_nBufSize = 0;
		m_nDataSize = 0;
		return S_OK;
	}

public:
	std_method_impl PutUByte(unsigned char nVal)
	{
		rc_assert((UCHAR_SIZE + m_nDataSize) < m_nBufSize, E_FAIL)
		Encode(m_pBuf + m_nDataSize, nVal);
		m_nDataSize += UCHAR_SIZE;
		return S_OK;
	}
	std_method_impl PutUShort(unsigned short nVal)
	{
		rc_assert((USHORT_SIZE + m_nDataSize) < m_nBufSize, E_FAIL)
		Encode(m_pBuf + m_nDataSize, nVal);
		m_nDataSize += USHORT_SIZE;
		return S_OK;
	}
	std_method_impl PutUInt(unsigned int nVal)
	{
		rc_assert((UINT_SIZE + m_nDataSize) < m_nBufSize, E_FAIL)
		Encode(m_pBuf + m_nDataSize, nVal);
		m_nDataSize += UINT_SIZE;
		return S_OK;
	}
	std_method_impl PutBytes(const unsigned char* pBytes, unsigned int nSize)
	{
		rc_assert(pBytes, E_INVALIDARG);
		rc_assert((nSize + m_nDataSize) < m_nBufSize, E_FAIL)
		s_memcpy(m_pBuf + m_nDataSize, pBytes, nSize);
		m_nDataSize += nSize; 
		return S_OK;
	}
	std_method_impl GetUByte(unsigned char& nVal, unsigned int offset)
	{
		nVal = m_pBuf[offset++];
		return S_OK;
	}
	std_method_impl GetUShort(unsigned short& nVal, unsigned int offset)
	{
		unsigned short hi = (unsigned char)m_pBuf[offset++];
		hi = hi << 8;
		hi |= (unsigned char)m_pBuf[offset++];
		nVal = hi;
		return S_OK;
	}
	std_method_impl GetUInt(unsigned int& nVal, unsigned int offset)
	{
		unsigned int a = (unsigned char)m_pBuf[offset++];
		unsigned int b = (unsigned char)m_pBuf[offset++];
		unsigned int c = (unsigned char)m_pBuf[offset++];
		unsigned int d = (unsigned char)m_pBuf[offset++];
		a = a << 24;
		a |= b << 16;
		a |= c << 8;
		a |= d;
		nVal = a;
		return S_OK;
	}
	std_method_impl GetBytes(unsigned char* pBytes, unsigned int nSize, unsigned int offset)
	{
		::memcpy(pBytes, m_pBuf + offset, nSize);
		return S_OK;
	}

private:

	size_t Encode(unsigned char* data, unsigned char i)
	{
		*data = i;
		return UCHAR_SIZE;
	}
	size_t Encode(unsigned char* data, unsigned short i)
	{
		unsigned short b = i;
		size_t nOffset(0);
		data[nOffset++] = (unsigned char)(0xFF & (b >> 8));
		data[nOffset++] = (unsigned char)(0xFF & (b));
		return USHORT_SIZE;
	}
	size_t Encode(unsigned char* data, unsigned int i)
	{
		unsigned int b = i;
		size_t nOffset(0);
		data[nOffset++] = (unsigned char)(0xFF & (b >> 24));
		data[nOffset++] = (unsigned char)(0xFF & (b >> 16));
		data[nOffset++] = (unsigned char)(0xFF & (b >> 8));
		data[nOffset++] = (unsigned char)(0xFF & (b));
		return UINT_SIZE;
	}
private:
	UCharArrayPtr			m_pBuf;
	unsigned int			m_nBufSize;
	mutable unsigned int	m_nDataSize;
};

#endif
